package com.example.demo.utils.date;

import org.apache.commons.lang3.StringUtils;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 日期通用工具类
 */
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
	// 偏移量正则
	private static final Pattern NON_PRINTABLE = Pattern
			.compile("^(\\-?|\\+?)((\\d*)y)?((\\d*)M)?((\\d*)d)?((\\d*)H)?((\\d*)m)?((\\d*)s)?$");
	public static final String yyyyMMddTHHmmssSSSSSSSXXX = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSSXXX";
	public static final String yyyyMMddTHHmmssSSSZ = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
	public static final String yyyyMMddHHmmssSSS = "yyyy-MM-dd HH:mm:ss.SSS";
	public static final String yyyyMMddHHmmss = "yyyy-MM-dd HH:mm:ss";
	public static final String yyyyMMddHHmm = "yyyy-MM-dd HH:mm";
	public static final String yyyyMMddHH = "yyyy-MM-dd HH";
	public static final String yyyyMMdd = "yyyy-MM-dd";
	public static final String yyyyMM = "yyyy-MM";
	public static final String yyyy = "yyyy";

	public static final String ddMMyyyyHHmmss = "dd-MM-yyyy HH:mm:ss";
	public static final String ddMMyyyyHHmm = "dd-MM-yyyy HH:mm";
	public static final String ddMMyyyy = "dd-MM-yyyy";

	public static final String _yyyyMMddHHmmssSSS = "yyyyMMddHHmmssSSS";
	public static final String _yyyyMMddHHmmss = "yyyyMMddHHmmss";
	public static final String _yyyyMMdd = "yyyyMMdd";
	public static final String _HHmmss = "HHmmss";
	public static final String HHMMSS = "HH:mm:ss";

	private static String[] parsePatterns = {
			"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
			"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
			"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};

	/**
	 * 存放日期格式map
	 */
	private static Map<String, DateFormat> formaters = null;

	/**
	 * 获取指定日期格式的dateformat对象
	 *
	 * @param format 指定日期格式
	 * @return
	 */
	public static DateFormat getDateFormater(String format) {
		if (formaters == null) {
			formaters = new HashMap<String, DateFormat>();
		}
		DateFormat formater = formaters.get(format);
		if (formater == null) {
			formater = new SimpleDateFormat(format);
			formaters.put(format, formater);
		}
		return formater;
	}

	/**
	 * 根据指定格式解析字符串，返回一个date对象
	 *
	 * @param strDate 指定字符串
	 * @param format 指定格式
	 * @return
	 */
	public static Date parse(String strDate, String format) {

		DateFormat formater = getDateFormater(format);
		synchronized (formater) {
			if(StringUtils.isEmpty(strDate)) {
				return null;
			}

			try {
				return formater.parse(strDate);
			} catch (ParseException e) {
				e.printStackTrace();
				return null;
			}
		}
	}

	/**
	 * 日期型字符串转化为日期 格式
	 */
	public static Date parseDate(Object str)
	{
		if (str == null)
		{
			return null;
		}
		try
		{
			return parseDate(str.toString(), parsePatterns);
		}
		catch (ParseException e)
		{
			return null;
		}
	}

	/**
	 * 将指定日历以指定格式格式化为字符串
	 *
	 * @param calendar 日历对象
	 * @param format 格式化对象
	 * @return 格式化后的字符串
	 */
	public static String format(Calendar calendar, String format) {
		return format(calendar.getTime(), format);
	}

	/**
	 * 将指定日期以指定格式格式化为字符串
	 *
	 * @param date 指定日期
	 * @param format 指定格式
	 * @return
	 */
	public static String format(Date date, String format) {
		if (date == null) {
			return StringUtils.EMPTY;
		}
		DateFormat formater = getDateFormater(format);
		synchronized (formater) {
			return formater.format(date);
		}
	}

	/**
	 * 将指定字符串格式的日期格式化为新格式的日期字符串
	 *
	 * @param strDate 指定字符串格式的日期
	 * @param srcFormat 该日期的原格式
	 * @param destFormat 新格式
	 * @return
	 */
	public static String format(String strDate, String srcFormat, String destFormat) {
		Date date = parse(strDate, srcFormat);
		return format(date, destFormat);
	}

	/**
	 * 根据年 周数 获取所在周开始(周一)的日期 AA
	 */
	public static Calendar toDateFromDate(int year, int month, int date) {
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.YEAR, year);
		calendar.set(Calendar.MONTH, month);
		calendar.set(Calendar.DAY_OF_MONTH, date);
		setTimeZero(calendar);
		return calendar;
	}

	/**
	 * 根据年 周数 获取所在周开始(周一)的日期 AA
	 */
	public static Calendar toDateFromWeek(int year, int week) {
		Calendar calendar = Calendar.getInstance();
		calendar.clear();
		calendar.set(Calendar.YEAR, year);
		calendar.set(Calendar.WEEK_OF_YEAR, week);
		calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
		return calendar;
	}

	/**
	 * 将指定年月日格式化为日期（sql.date）类对象
	 *
	 * @param year 指定年
	 * @param month 指定月
	 * @param date 指定日
	 * @return
	 */
	public static java.sql.Date createSqlDate(int year, int month, int date) {
		Calendar calendar = Calendar.getInstance();
		calendar.set(year, month, date);
		return new java.sql.Date(calendar.getTimeInMillis());
	}

	/**
	 * 将util.date类日期转换为sql.date类日期
	 *
	 * @param date
	 * @return
	 */
	public static Date createSqlDate(Date date) {
		return new java.sql.Date(date.getTime());
	}

	/**
	 * 将指定日期时间时间设置为0时0分0秒0毫秒
	 *
	 * @param date 指定时间
	 * @return
	 */
	public static void toStartOfDay(Calendar calendar) {
		setTimeZero(calendar);
	}

	/**
	 * 将指定日期时间时间设置为0时0分0秒0毫秒
	 *
	 * @param date 指定时间
	 * @return
	 */
	public static Date toStartOfDay(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		toStartOfDay(calendar);
		return calendar.getTime();
	}

	/**
	 * 将指定日期时间设置为23时59分59秒999毫秒
	 *
	 * @param date 指定时间
	 * @return
	 */
	public static void toEndOfDay(Calendar calendar) {
		setTimeMax(calendar);
	}

	/**
	 * 将指定日期时间设置为23时59分59秒999毫秒
	 *
	 * @param date 指定时间
	 * @return
	 */
	public static Date toEndOfDay(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		setTimeMax(calendar);
		return calendar.getTime();
	}

	/**
	 * 将指定日期时间时间设置为0时0分0秒0毫秒
	 *
	 * @param date 指定时间
	 * @return
	 */
	public static Date toStartOfLastDay(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		setTimeZero(calendar);
		calendar.add(Calendar.DATE, -1);// 取前一天

		return calendar.getTime();
	}

	/**
	 * 将指定日期时间设置为23时59分59秒999毫秒
	 *
	 * @param date 指定时间
	 * @return
	 */
	public static Date toEndOfLastDay(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		setTimeMax(calendar);
		calendar.add(Calendar.DATE, -1);// 取前一天

		return calendar.getTime();
	}

	/**
	 * 将指定日期设置为完整日期时间
	 *
	 * @param date 指定日期
	 * @return
	 */
	public static Date toDayTime(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		return calendar.getTime();
	}

	/**
	 * 比较两个日期的前后关系
	 *
	 * @param date1 用于比价的日期
	 * @param date2 用于比较的日期
	 * @return date1早于date2则返回true
	 */
	public static boolean compareDate(Date date1, Date date2) {
		int n = date1.compareTo(date2);
		if (n < 0) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 在指定日期后增加月数
	 *
	 * @param date 指定日期
	 * @param months 增加的月数
	 * @return 增加天数后日期
	 */
	public static Date addMonths(Date date, int months) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.add(Calendar.MONTH, months);
		return cal.getTime();
	}

	/**
	 * 在指定日期后增加天数
	 *
	 * @param date 指定日期
	 * @param days 增加的天数
	 * @return 增加天数后日期
	 */
	public static Date addDays(Date date, int days) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.add(Calendar.DAY_OF_YEAR, days);
		return cal.getTime();
	}

	/**
	 * 在指定日期后增加数天
	 *
	 * @param date 指定日期
	 * @param hours 增加的小时
	 * @return 增加天数后日期
	 */
	public static Date addHours(Date date, int hours) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.add(Calendar.HOUR_OF_DAY, hours);
		return cal.getTime();
	}

	/**
	 * 在指定日期后增加分钟
	 *
	 * @param date 指定日期
	 * @param minutes 增加的分钟
	 * @return 增加分钟后时间
	 */
	public static Date addMinutes(Date date, int minutes) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.add(Calendar.MINUTE, minutes);
		return cal.getTime();
	}

	public static Date addSeconds(Date date, int seconds) {
		if(seconds == 0) {
			return date;
		}
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.add(Calendar.SECOND, seconds);
		return cal.getTime();
	}

	/**
	 * 根据传入的数据统计模式来统计数据，目前有两种，求平均（AVG）和求和(SUM)
	 *
	 * @param statMode 数据统计模式，enum类
	 * @param numbers 要统计的数据list
	 * @return 如果传入的统计模式为AVG或SUM，则返回BigDecimal型的值，如果是其他的统计模式，则返回0
	 */
	public static Date calc(Date date, String offset) {
		if (date == null || StringUtils.isEmpty(offset)) {
			return date;
		}

		Calendar gc = Calendar.getInstance();
		gc.setTime(date);

		int sign = 1;
		Matcher m = NON_PRINTABLE.matcher(offset);
		if (m.find()) {
			if (m.group(1) != null) {
				sign = -1;
			}

			if (m.group(3) != null) {
				int year = Integer.parseInt(m.group(3)) * sign;
				gc.add(Calendar.YEAR, year);
			}

			if (m.group(5) != null) {
				int month = Integer.parseInt(m.group(5)) * sign;
				gc.add(Calendar.MONTH, month);
			}

			if (m.group(7) != null) {
				int day = Integer.parseInt(m.group(7)) * sign;
				gc.add(Calendar.DATE, day);
			}

			if (m.group(9) != null) {
				int hour = Integer.parseInt(m.group(9)) * sign;
				gc.add(Calendar.HOUR_OF_DAY, hour);
			}

			if (m.group(11) != null) {
				int minute = Integer.parseInt(m.group(11)) * sign;
				gc.add(Calendar.MINUTE, minute);
			}

			if (m.group(13) != null) {
				int minute = Integer.parseInt(m.group(13)) * sign;
				gc.add(Calendar.SECOND, minute);
			}
		}

		return gc.getTime();
	}

	/**
	 * 取得指定日期所在的周一凌晨时间
	 *
	 * @param date 指定时间
	 * @return 返回指定日期所在的周一凌晨时间
	 */
	public static Date toStartOfThisWeek(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		setTimeZero(calendar);

		// 周一是一周第一天，周日是最后一天
		calendar.add(Calendar.DATE, -1 * calendar.get(Calendar.DAY_OF_WEEK) + 2);
		return calendar.getTime();
	}

	/**
	 * 取得指定日期所在的周日23:59时间
	 *
	 * @param date 指定时间
	 * @return 返回指定日期所在的周日时间
	 */
	public static Date toEndOfThisWeek(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		setTimeMax(calendar);
		// 周一是一周第一天，周日是最后一天
		calendar.add(Calendar.DATE, -1 * calendar.get(Calendar.DAY_OF_WEEK) + 1 + 7);

		return calendar.getTime();
	}

	/**
	 * 取得指定时间的上周周一
	 *
	 * @param date 指定时间
	 * @return
	 */
	public static Date toStartOfLastWeek(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		setTimeZero(calendar);

		// 周一是一周第一天，周日是最后一天
		calendar.add(Calendar.DATE, -1 * calendar.get(Calendar.DAY_OF_WEEK) + 2 - 7);
		return calendar.getTime();
	}

	/**
	 * 取得指定时间的上周周日
	 *
	 * @param date 指定时间
	 * @return
	 */
	public static Date toEndOfLastWeek(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		setTimeMax(calendar);
		// 周一是一周第一天，周日是最后一天
		calendar.add(Calendar.DATE, -1 * calendar.get(Calendar.DAY_OF_WEEK) + 1);

		return calendar.getTime();
	}

	/**
	 * 取得指定时间的本月1号
	 *
	 * @param date 指定时间
	 * @return
	 */
	public static Date toStartOfThisMonth(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		setTimeZero(calendar);

		calendar.set(Calendar.DAY_OF_MONTH, 1);

		return calendar.getTime();
	}

	/**
	 * 取得指定时间的本月最后一天
	 *
	 * @param date 指定时间
	 * @return
	 */
	public static Date toEndOfThisMonth(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);

		// 将date后推一个月
		int month = calendar.get(Calendar.MONTH);
		if (month == Calendar.DECEMBER) {
			calendar.set(Calendar.MONTH, Calendar.JANUARY);
			calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) + 1);
		} else {
			calendar.set(Calendar.MONTH, 1 + month);
		}

		// 通过取得上个月最后一天的方式取得当前月最后一天
		calendar.add(Calendar.DATE, -1 * calendar.get(Calendar.DAY_OF_MONTH));
		setTimeMax(calendar);

		return calendar.getTime();
	}

	/**
	 * 取得指定时间的上个月第一天
	 *
	 * @param date 指定时间
	 * @return
	 */
	public static Date toStartOfLastMonth(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);

		setTimeZero(calendar);

		// 取得上个月最后一天
		calendar.add(Calendar.DATE, -1 * calendar.get(Calendar.DAY_OF_MONTH));

		calendar.set(Calendar.DAY_OF_MONTH, 1);

		return calendar.getTime();
	}

	/**
	 * 取得指定时间的上个月最后一天
	 *
	 * @param date 指定时间
	 * @return
	 */
	public static Date toEndOfLastMonth(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		setTimeMax(calendar);

		// 取得上个月最后一天
		calendar.add(Calendar.DATE, -1 * calendar.get(Calendar.DAY_OF_MONTH));

		return calendar.getTime();
	}

	/**
	 * 取得指定时间的本季度第一天
	 *
	 * @param date 指定时间
	 * @return
	 */
	public static Date toStartOfThisQuarter(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		setTimeZero(calendar);

		calendar.set(Calendar.DAY_OF_MONTH, 1);
		// 取本季度开始月
		calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) / 3 * 3);

		return calendar.getTime();
	}

	/**
	 * 取得指定时间的本季度最后一天
	 *
	 * @param date 指定时间
	 * @return
	 */
	public static Date toEndOfThisQuarter(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.DAY_OF_MONTH, 1);

		// 取得下个季度的开始日期，往前推一天
		int month = calendar.get(Calendar.MONTH);
		if (month >= Calendar.OCTOBER) {
			calendar.set(Calendar.MONTH, Calendar.JANUARY);
			calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) + 1);
		} else {
			calendar.set(Calendar.MONTH, 3 + month);
		}
		calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) / 3 * 3);

		calendar.add(Calendar.DATE, -1);
		setTimeMax(calendar);

		return calendar.getTime();
	}

	/**
	 * 取得指定时间的上个季度第一天
	 *
	 * @param date 指定时间
	 * @return
	 */
	public static Date toStartOfLastQuarter(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		setTimeZero(calendar);

		calendar.set(Calendar.DAY_OF_MONTH, 1);

		// 取上季度开始月,如果是负数，则上季度开始日期是去年的10月
		int month = calendar.get(Calendar.MONTH) / 3 * 3 - 3;
		if (month == -3) {
			month = Calendar.OCTOBER;
			calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) - 1);
		}

		calendar.set(Calendar.MONTH, month);

		return calendar.getTime();
	}

	/**
	 * 取得指定时间的本季度最后一天
	 *
	 * @param date 指定时间
	 * @return
	 */
	public static Date toEndOfLastQuarter(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.DAY_OF_MONTH, 1);

		// 取得本季度的开始日期，往前推一天
		calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) / 3 * 3);

		calendar.add(Calendar.DATE, -1);
		setTimeMax(calendar);

		return calendar.getTime();
	}

	/**
	 * 取得本年第一天
	 *
	 * @param date 指定时间
	 * @return
	 */
	public static Date toStartOfThisYear(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		calendar.set(Calendar.MONTH, Calendar.JANUARY);
		setTimeZero(calendar);

		return calendar.getTime();
	}

	/**
	 * 取得本年最后一天
	 *
	 * @param date 指定时间
	 * @return
	 */
	public static Date toEndOfThisYear(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.DAY_OF_MONTH, 30);
		calendar.set(Calendar.MONTH, Calendar.DECEMBER);
		setTimeMax(calendar);

		return calendar.getTime();
	}

	/**
	 * 取得去年第一天
	 *
	 * @param date 指定时间
	 * @return
	 */
	public static Date toStartOfLastYear(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		calendar.set(Calendar.MONTH, Calendar.JANUARY);
		calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) - 1);
		setTimeZero(calendar);

		return calendar.getTime();
	}

	/**
	 * 取得去年最后一天
	 *
	 * @param date 指定时间
	 * @return
	 */
	public static Date toEndOfLastYear(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.DAY_OF_MONTH, 30);
		calendar.set(Calendar.MONTH, Calendar.DECEMBER);
		calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) - 1);
		setTimeMax(calendar);

		return calendar.getTime();
	}

	/**
	 * 取得指定日期指定的过去天数开始日期
	 *
	 * @param date 指定时间
	 * @param beforeDays 指定过去天数
	 * @return
	 */
	public static Date toStartOfLastDays(Date date, int beforeDays) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		int inputDayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
		calendar.set(Calendar.DAY_OF_YEAR, inputDayOfYear - beforeDays);
		setTimeZero(calendar);

		return calendar.getTime();
	}

	/**
	 * 取得指定日期指定的过去天数结束日期
	 *
	 * @param date 指定时间
	 * @param beforeDays 指定过去天数
	 * @return
	 */
	public static Date toEndOfLastDays(Date date, int beforeDays) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		int inputDayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
		calendar.set(Calendar.DAY_OF_YEAR, inputDayOfYear - beforeDays);
		setTimeMax(calendar);

		return calendar.getTime();
	}

	/**
	 * 将指定日期时间时间设置为0时0分0秒0毫秒
	 *
	 * @param date 指定时间
	 * @return
	 */
	public static void toStartOfMonth(Calendar calendar) {
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		calendar.set(Calendar.MILLISECOND, 0);
	}

	/**
	 * 将指定日期时间时间设置为0时0分0秒0毫秒
	 *
	 * @param date 指定时间
	 * @return
	 */
	public static void toStartOfHour(Calendar calendar) {
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		calendar.set(Calendar.MILLISECOND, 0);
	}

	private static void setTimeZero(Calendar calendar) {
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		calendar.set(Calendar.MILLISECOND, 0);
	}

	private static void setTimeMax(Calendar calendar) {
		calendar.set(Calendar.HOUR_OF_DAY, 23);
		calendar.set(Calendar.MINUTE, 59);
		calendar.set(Calendar.SECOND, 59);
		calendar.set(Calendar.MILLISECOND, 999);
	}

	/**
	 * 判断指定时间是否是今天
	 *
	 * @param f 格式化对象
	 * @return 日期字符串
	 */
	public static boolean isToday(Date date) {
		return isSameDay(date, new Date());
	}

	/**
	 * 判断指定时间是否是今天
	 *
	 * @param f 格式化对象
	 * @return 日期字符串
	 */
	public static boolean isToday(Calendar calendar) {
		return isSameDay(calendar, Calendar.getInstance());
	}

	/**
	 * 判断是否是同一天
	 *
	 * @param cal1 第一个日期
	 * @param cal2 第二个日期
	 * @return 如果相同则返回true，则返回false
	 */
	public static boolean isSameDay(Calendar cal1, Calendar cal2) {
		if (cal1 == null || cal2 == null) {
			throw new IllegalArgumentException("两个日期都不能为null");
		}
		return (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) && cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && cal1
				.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR));
	}

	/**
	 * 判断是否是同一天
	 *
	 * @param cal1 第一个日期
	 * @param cal2 第二个日期
	 * @return 如果相同则返回true，则返回false
	 */
	public static boolean isSameDay(Date date1, Date date2) {
		if (date1 == null || date2 == null) {
			throw new IllegalArgumentException("The date must not be null");
		}
		Calendar cal1 = Calendar.getInstance();
		cal1.setTime(date1);
		Calendar cal2 = Calendar.getInstance();
		cal2.setTime(date2);
		return isSameDay(cal1, cal2);
	}

	/**
	 * 获取两个日期之间的日期集合
	 *
	 * @param startDate 开始日期
	 * @param endDate 结束日期
	 * @return 所有天的列表
	 */
	public static List<Date> listDays(Date startDate, Date endDate) {
		Calendar startCalendar = Calendar.getInstance();
		startCalendar.setTime(startDate);
		startCalendar.set(Calendar.HOUR_OF_DAY, 0);

		Calendar endCalendar = Calendar.getInstance();
		endCalendar.setTime(endDate);
		endCalendar.set(Calendar.HOUR_OF_DAY, 0);

		List<Date> dates = new ArrayList<>();
		while (startCalendar.before(endCalendar)) {
			dates.add(startCalendar.getTime());
			startCalendar.add(Calendar.DATE, 1);
		}

		return dates;
	}

	/**
	 * 获取两个日期之间的小时(不足一小时的时间按照一小时计算)
	 *
	 * @param startDate 开始时间
	 * @param endDate 结束时间
	 * @return 两个日期之间的小时数量
	 */
	public static int statHourCount(Calendar startDate, Calendar endDate) {
		return statHourCount(startDate.getTime(), endDate.getTime());
	}

	/**
	 * 获取两个日期之间的小时(不足一小时的时间按照一小时计算)
	 *
	 * @param startDate 开始时间
	 * @param endDate 结束时间
	 * @return 两个日期之间的小时数量
	 */
	public static int statHourCount(Date startDate, Date endDate) {
		long nh = 1000 * 60 * 60;// 一小时的毫秒数
		long diff = endDate.getTime() - startDate.getTime();
		int count = (int) (diff / nh);
		if (diff % nh > 0) {
			count++;
		}
		return count;
	}

	/**
	 * 获取两个日期之间的天的数量(不足一天的时间按照一小时计算)
	 *
	 * @param startDate 开始时间
	 * @param endDate 结束时间
	 * @return 两个日期之间的天的数量
	 */
	public static int statDayCount(Calendar startDate, Calendar endDate) {
		return statDayCount(startDate.getTime(), endDate.getTime());
	}

	/**
	 * 获取两个日期之间的小时(不足一小时的时间按照一小时计算)
	 *
	 * @param startDate 开始时间
	 * @param endDate 结束时间
	 * @return 两个日期之间的小时数量
	 */
	public static int statDayCount(Date startDate, Date endDate) {
		long nh = 1000 * 3600 * 24;// 一天的毫秒数
		long diff = endDate.getTime() - startDate.getTime();
		int count = (int) (diff / nh);
		if (diff % nh > 0) {
			count++;
		}
		return count;
	}

	/**
	 * 获取两个日期之间的周的数量(不足一小时的时间按照一小时计算)
	 *
	 * @param startDate 开始时间
	 * @param endDate 结束时间
	 * @return 两个日期之间的周的数量
	 */
	public static int statWeekCount(Calendar startDate, Calendar endDate) {
		return statWeekCount(startDate.getTime(), endDate.getTime());
	}

	/**
	 * 获取两个日期之间的小时(不足一小时的时间按照一小时计算)
	 *
	 * @param startDate 开始时间
	 * @param endDate 结束时间
	 * @return 两个日期之间的小时数量
	 */
	public static int statWeekCount(Date startDate, Date endDate) {
		int dayCount = statDayCount(startDate, endDate);
		int count = (int) (dayCount / 7);
		if (dayCount % 7 > 0) {
			count++;
		}
		return count;
	}

	/**
	 * 获取两个日期之间的月的数量(不足一个月的时间按照一个月计算)
	 *
	 * @param startCalendar 开始时间
	 * @param endCalendar 结束时间
	 * @return 两个日期之间的月的数量
	 */
	public static int statMonthCount(Calendar startCalendar, Calendar endCalendar) {
		int startYear = startCalendar.get(Calendar.YEAR);
		int srartMonth = startCalendar.get(Calendar.MONTH);
		int srartDate = startCalendar.get(Calendar.DAY_OF_MONTH);

		int endYear = endCalendar.get(Calendar.YEAR);
		int endMonth = endCalendar.get(Calendar.MONTH);
		int endDate = endCalendar.get(Calendar.DAY_OF_MONTH);

		int count = 0;
		if(startYear == endYear) {
			count = endMonth - srartMonth;
		}else {
			count = (12 - srartMonth);
			if((endYear - 1) >= (startYear + 1)) {
				count += ((endYear - 1) - (startYear + 1) + 1) * 12;
			}
			count += (endMonth + 1);
		}

		if(endDate > srartDate) {
			count ++;
		}

		return count;
	}

	/**
	 * 获取两个日期之间的小时数 AA
	 *
	 * @param startDate
	 * @param endDate
	 * @return
	 */
	public static int statMonthCount(Date startDate, Date endDate) {
		Calendar startCalendar = Calendar.getInstance();
		startCalendar.setTime(startDate);
		Calendar endCalendar = Calendar.getInstance();
		endCalendar.setTime(endDate);
		return statMonthCount(startCalendar, endCalendar);
	}

	public static Calendar toFirstDayOfVerticaWeek(int year, int week) {
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.YEAR, year);
		calendar.set(Calendar.MONTH, 0);
		calendar.set(Calendar.DAY_OF_MONTH, 4);
		calendar = toFirstDayOfWeek(calendar);
		calendar.add(Calendar.DAY_OF_YEAR, (week - 1) * 7);

		return calendar;
	}

	/**
	 * 把日期转换成该周的周一对应的日期
	 *
	 * @param calendar Calendar对象
	 * @return Calendar对象
	 */
	public static Calendar toFirstDayOfWeek(Calendar calendar) {
		int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
		int dayCount = 0;
		if (dayOfWeek == Calendar.SUNDAY) {
			dayCount = 6;
		} else {
			dayCount = dayOfWeek - Calendar.MONDAY;
		}

		calendar.add(Calendar.DAY_OF_YEAR, - dayCount);
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		calendar.set(Calendar.MILLISECOND, 0);
		return calendar;
	}

	/**
	 * 根据指定格式解析字符串，返回一个date对象
	 *
	 * @param strDate 指定字符串
	 * @param format 指定格式
	 * @return
	 */
	public static Calendar toCalendar(String strDate, String format) {
		try {
			DateFormat formater = getDateFormater(format);
			synchronized (formater) {
				Date date = formater.parse(strDate);
				Calendar calendar = Calendar.getInstance();
				calendar.setTime(date);
				return calendar;
			}
		} catch (ParseException e) {
			e.printStackTrace();
			return null;
		}
	}

	public static void main(String[] args) {
		Calendar calendar = Calendar.getInstance();
		System.out.println();
		calendar = toFirstDayOfWeek(calendar);
		System.out.println(format(calendar, yyyyMMddHHmmssSSS));
	}

	public static Calendar create(int year, int month) {
		return create(year, month, 1);
	}

	public static Calendar create(int year, int month, int day) {
		return create(year, month, day, 0);
	}

	public static Calendar create(int year, int month, int date, int hour) {
		return create(year, month, date, hour, 0, 0, 0);
	}

	public static Calendar create(int year, int month, int date, int hour, int minute, int second, int millisecond) {
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.YEAR, year);
		calendar.set(Calendar.MONTH, month);
		calendar.set(Calendar.DAY_OF_MONTH, date);
		calendar.set(Calendar.HOUR_OF_DAY, hour);
		calendar.set(Calendar.MINUTE, minute);
		calendar.set(Calendar.SECOND, second);
		calendar.set(Calendar.MILLISECOND, millisecond);
		return calendar;
	}

	public static Calendar createByWeek(int year, int week) {
		Calendar calendar = create(year, 0, 0, 0, 0, 0, 0);
		calendar.set(Calendar.WEEK_OF_YEAR, week);
		return calendar;
	}

	/**
	 * 计算减去指定秒数的时间
	 *
	 * @param date 指定日期
	 * @return 指定日期
	 */
	public static Date subSeconds(Date date, long seconds) {
		long time = date.getTime();
		time -= seconds * 1000;
		date.setTime(time);
		return date;
	}

	/**
	 * 计算减去指定分钟数的时间
	 *
	 * @param date 指定日期
	 * @return 指定日期
	 */
	public static Date subMinutes(Date date, long minute) {

		return subSeconds(date, minute * 60);
	}

	/**
	 * 计算减去指定分钟数的时间
	 *
	 * @param date 指定日期
	 * @return 指定日期
	 */
	public static Date subDay(Date date, long hour) {
		return subMinutes(date, hour * 60);
	}

	/**
	 * unix时间转换成普通时间的字符串类型
	 *
	 * @param unixTime unix时间戳
	 * @return 【yyyy-MM-dd HH:mm:ss】时间类型
	 */
	public static String unixToDate(String unixTime) {
	    Long timestamp = Long.parseLong(unixTime)*1000;
	    String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(timestamp));
	    return date;
	}

	/**
	 * Date类型转换成unix时间
	 *
	 * @param date Date时间
	 * @return unix时间戳
	 */
	public static long dateToUnix(Date date) {
		long times = date.getTime()/1000;
		return times;
	}

	/**
	 * 总秒数转换成时分秒
	 *
	 * @param ss  总秒数
	 * @return 时分秒
	 */
	public static String secondsToHms(int ss) {
		int hours = ss/3600;
		int minutes = (ss%3600)/60;
		int seconds = (ss%3600)%60;

		String time = "";
		if (hours>0){
			time += hours + "小时";
		}
		if (minutes>0){
			time += minutes + "分";
		}
		if (seconds>0){
			time += seconds + "秒";
		}
	    return time;
	}

	public static long interval(Date date1, Date date2) {
		return Math.abs(date1.getTime() - date2.getTime());
	}

	public static long secondInterval(Date date1, Date date2) {
		return interval(date1, date2) / 1000;
	}

	public static long minuteInterval(Date date1, Date date2) {
		return secondInterval(date1, date2) / 60;
	}

	public static long hourInterval(Date date1, Date date2) {
		return secondInterval(date1, date2) / 60;
	}

	public static Date now(){
		return new Date();
	}

	public static String nowTime() { return format(new Date(), yyyyMMddHHmmss); }

	public static LocalDate date2LocalDate(Date date) {
		if(null == date) {
			return null;
		}
		return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
	}
}
